﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace tamzarian
{
    /// <summary>
    /// Dual Quaternion q0 + ε * qe
    /// where ε is the Dual unit satisfying ε^2 = 0
    /// </summary>
    public class DualQuaternion
    {
        public readonly Quaternion q0;
        public readonly Quaternion qe;

        public DualQuaternion(Quaternion q0, Quaternion qe)
        {
            this.q0 = q0;
            this.qe = qe;
        }

        public DualQuaternion(Dual w, Dual x, Dual y, Dual z)
            : this(new Quaternion(w.a0, x.a0, y.a0, z.a0),
                   new Quaternion(w.ae, x.ae, y.ae, z.ae))
        {
        }

        public DualQuaternion(
            double w0, double we,
            double x0, double xe,
            double y0, double ye,
            double z0, double ze)
            : this(new Quaternion(w0, x0, y0, z0),
                   new Quaternion(we, xe, ye, ze))
        {
        }

        #region Override Object Methods

        public override string ToString()
        {
            return string.Format("DualQuaternion({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7})",
                q0.W, qe.W, q0.X, qe.X, q0.Y, qe.Y, q0.Z, qe.Z);
        }

        public override int GetHashCode()
        {
            return q0.GetHashCode() ^
                   qe.GetHashCode();
        }

        public override bool Equals(object other)
        {
            return other is DualQuaternion && Equals((DualQuaternion)other);
        }

        public override bool Equals(DualQuaternion other)
        {
            return q0 == other.q0 &&
                   qe == other.qe;
        }

        public static bool operator ==(Dual lhs, Dual rhs)
        {
            return lhs.Equals(rhs);
        }

        public static bool operator !=(Dual lhs, Dual rhs)
        {
            return !lhs.Equals(rhs);
        }

        #endregion

        #region Arithmetic

        public static DualQuaternion operator +(DualQuaternion lhs, DualQuaternion rhs)
        {
            return new DualQuaternion(lhs.q0 + rhs.q0, lhs.qe + rhs.qe);
        }

        public static DualQuaternion operator *(DualQuaternion lhs, DualQuaternion rhs)
        {
            return new DualQuaternion(lhs.q0 * rhs.q0, lhs.q0 * rhs.qe + lhs.qe * rhs.q0);
        }

        public DualQuaternion Conjugate()
        {
            return new DualQuaternion(q0.Conjugate(), qe.Conjugate());
        }

        #endregion
    }
}
